﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace Nes.Core
{


    public class OpCode
    {
        #region Const Opcode
        public const Int32 INS_ADC = 0;
        public const Int32 INS_AND = 1;
        public const Int32 INS_ASL = 2;

        public const Int32 INS_BCC = 3;
        public const Int32 INS_BCS = 4;
        public const Int32 INS_BEQ = 5;
        public const Int32 INS_BIT = 6;
        public const Int32 INS_BMI = 7;
        public const Int32 INS_BNE = 8;
        public const Int32 INS_BPL = 9;
        public const Int32 INS_BRK = 10;
        public const Int32 INS_BVC = 11;
        public const Int32 INS_BVS = 12;
        public const Int32 INS_CLC = 13;
        public const Int32 INS_CLD = 14;
        public const Int32 INS_CLI = 15;
        public const Int32 INS_CLV = 16;
        public const Int32 INS_CMP = 17;
        public const Int32 INS_CPX = 18;
        public const Int32 INS_CPY = 19;
        public const Int32 INS_DEC = 20;
        public const Int32 INS_DEX = 21;
        public const Int32 INS_DEY = 22;
        public const Int32 INS_EOR = 23;
        public const Int32 INS_INC = 24;
        public const Int32 INS_INX = 25;
        public const Int32 INS_INY = 26;
        public const Int32 INS_JMP = 27;
        public const Int32 INS_JSR = 28;
        public const Int32 INS_LDA = 29;
        public const Int32 INS_LDX = 30;
        public const Int32 INS_LDY = 31;
        public const Int32 INS_LSR = 32;
        public const Int32 INS_NOP = 33;
        public const Int32 INS_ORA = 34;
        public const Int32 INS_PHA = 35;
        public const Int32 INS_PHP = 36;
        public const Int32 INS_PLA = 37;
        public const Int32 INS_PLP = 38;
        public const Int32 INS_ROL = 39;
        public const Int32 INS_ROR = 40;
        public const Int32 INS_RTI = 41;
        public const Int32 INS_RTS = 42;
        public const Int32 INS_SBC = 43;
        public const Int32 INS_SEC = 44;
        public const Int32 INS_SED = 45;
        public const Int32 INS_SEI = 46;
        public const Int32 INS_STA = 47;
        public const Int32 INS_STX = 48;
        public const Int32 INS_STY = 49;
        public const Int32 INS_TAX = 50;
        public const Int32 INS_TAY = 51;
        public const Int32 INS_TSX = 52;
        public const Int32 INS_TXA = 53;
        public const Int32 INS_TXS = 54;
        public const Int32 INS_TYA = 55;
        public const Int32 INS_ALR = 56;
        public const Int32 INS_ANC = 57;
        public const Int32 INS_ARR = 58;
        public const Int32 INS_AXS = 59;
        public const Int32 INS_LAX = 60;
        public const Int32 INS_SAX = 61;
        public const Int32 INS_DCP = 62;
        public const Int32 INS_ISC = 63;
        public const Int32 INS_RLA = 64;
        public const Int32 INS_RRA = 65;
        public const Int32 INS_SLO = 66;
        public const Int32 INS_SRE = 67;
        public const Int32 INS_SKB = 68;
        public const Int32 INS_IGN = 69;

        public const Int32 INS_DUMMY = 70; // dummy instruction used for 'halting' the processor some cycles
        #endregion

        #region Addressing modes:
        public const Byte ADDR_ZP = 0;
        public const Byte ADDR_REL = 1;
        public const Byte ADDR_IMP = 2;
        public const Byte ADDR_ABS = 3;
        public const Byte ADDR_ACC = 4;
        public const Byte ADDR_IMM = 5;
        public const Byte ADDR_ZPX = 6;
        public const Byte ADDR_ZPY = 7;
        public const Byte ADDR_ABSX = 8;
        public const Byte ADDR_ABSY = 9;
        public const Byte ADDR_IDX = 10;
        public const Byte ADDR_IDY = 11;
        public const Byte ADDR_INDABS = 12;
        #endregion

        #region 指令名称 和 寻址模式名称
        /// <summary>
        /// 指令名称
        /// </summary>
        public static readonly String[] InstName = [
            "ADC",
            "AND",
            "ASL",
            "BCC",
            "BCS",
            "BEQ",
            "BIT",
            "BMI",
            "BNE",
            "BPL",
            "BRK",
            "BVC",
            "BVS",
            "CLC",
            "CLD",
            "CLI",
            "CLV",
            "CMP",
            "CPX",
            "CPY",
            "DEC",
            "DEX",
            "DEY",
            "EOR",
            "INC",
            "INX",
            "INY",
            "JMP",
            "JSR",
            "LDA",
            "LDX",
            "LDY",
            "LSR",
            "NOP",
            "ORA",
            "PHA",
            "PHP",
            "PLA",
            "PLP",
            "ROL",
            "ROR",
            "RTI",
            "RTS",
            "SBC",
            "SEC",
            "SED",
            "SEI",
            "STA",
            "STX",
            "STY",
            "TAX",
            "TAY",
            "TSX",
            "TXA",
            "TXS",
            "TYA",
            "ALR",
            "ANC",
            "ARR",
            "AXS",
            "LAX",
            "SAX",
            "DCP",
            "ISC",
            "RLA",
            "RRA",
            "SLO",
            "SRE",
            "SKB",
            "IGN",
            ];

        public readonly String[] AddrModel = [
            "Zero Page           ",
            "Relative            ",
            "Implied             ",
            "Absolute            ",
            "Accumulator         ",
            "Immediate           ",
            "Zero Page,X         ",
            "Zero Page,Y         ",
            "Absolute,X          ",
            "Absolute,Y          ",
            "Preindexed Indirect ",
            "Postindexed Indirect",
            "Indirect Absolute   "
            ];
        #endregion

        /// <summary>
        /// 对应指令需要的cpu时钟数量字典
        /// </summary>
        private Int32[] CycTable = new Int32[]{
              /*0x00*/ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
              /*0x10*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
              /*0x20*/ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
              /*0x30*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
              /*0x40*/ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
              /*0x50*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
              /*0x60*/ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
              /*0x70*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
              /*0x80*/ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
              /*0x90*/ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
              /*0xA0*/ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
              /*0xB0*/ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4,
              /*0xC0*/ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
              /*0xD0*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
              /*0xE0*/ 2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
              /*0xF0*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7
            };

        private static Byte[][] Opcodes { get; set; }

        public static Byte[][] GetOpCodes()
        {
            InitOpcode();
            return Opcodes;
        }

        private static void InitOpcode()
        {
            Opcodes = new Byte[256][];
            // ADC:
            SetOp(INS_ADC, 0x69, ADDR_IMM, 2, 2);
            SetOp(INS_ADC, 0x65, ADDR_ZP, 2, 3);
            SetOp(INS_ADC, 0x75, ADDR_ZPX, 2, 4);
            SetOp(INS_ADC, 0x6d, ADDR_ABS, 3, 4);
            SetOp(INS_ADC, 0x7d, ADDR_ABSX, 3, 4);
            SetOp(INS_ADC, 0x79, ADDR_ABSY, 3, 4);
            SetOp(INS_ADC, 0x61, ADDR_IDX, 2, 6);
            SetOp(INS_ADC, 0x71, ADDR_IDY, 2, 5);

            // AND:
            SetOp(INS_AND, 0x29, ADDR_IMM, 2, 2);
            SetOp(INS_AND, 0x25, ADDR_ZP, 2, 3);
            SetOp(INS_AND, 0x35, ADDR_ZPX, 2, 4);
            SetOp(INS_AND, 0x2d, ADDR_ABS, 3, 4);
            SetOp(INS_AND, 0x3d, ADDR_ABSX, 3, 4);
            SetOp(INS_AND, 0x39, ADDR_ABSY, 3, 4);
            SetOp(INS_AND, 0x21, ADDR_IDX, 2, 6);
            SetOp(INS_AND, 0x31, ADDR_IDY, 2, 5);

            // ASL:
            SetOp(INS_ASL, 0x0a, ADDR_ACC, 1, 2);
            SetOp(INS_ASL, 0x06, ADDR_ZP, 2, 5);
            SetOp(INS_ASL, 0x16, ADDR_ZPX, 2, 6);
            SetOp(INS_ASL, 0x0e, ADDR_ABS, 3, 6);
            SetOp(INS_ASL, 0x1e, ADDR_ABSX, 3, 7);

            // BCC:
            SetOp(INS_BCC, 0x90, ADDR_REL, 2, 2);

            // BCS:
            SetOp(INS_BCS, 0xb0, ADDR_REL, 2, 2);

            // BEQ:
            SetOp(INS_BEQ, 0xf0, ADDR_REL, 2, 2);

            // BIT:
            SetOp(INS_BIT, 0x24, ADDR_ZP, 2, 3);
            SetOp(INS_BIT, 0x2c, ADDR_ABS, 3, 4);

            // BMI:
            SetOp(INS_BMI, 0x30, ADDR_REL, 2, 2);

            // BNE:
            SetOp(INS_BNE, 0xd0, ADDR_REL, 2, 2);

            // BPL:
            SetOp(INS_BPL, 0x10, ADDR_REL, 2, 2);

            // BRK:
            SetOp(INS_BRK, 0x00, ADDR_IMP, 1, 7);

            // BVC:
            SetOp(INS_BVC, 0x50, ADDR_REL, 2, 2);

            // BVS:
            SetOp(INS_BVS, 0x70, ADDR_REL, 2, 2);

            // CLC:
            SetOp(INS_CLC, 0x18, ADDR_IMP, 1, 2);

            // CLD:
            SetOp(INS_CLD, 0xd8, ADDR_IMP, 1, 2);

            // CLI:
            SetOp(INS_CLI, 0x58, ADDR_IMP, 1, 2);

            // CLV:
            SetOp(INS_CLV, 0xb8, ADDR_IMP, 1, 2);

            // CMP:
            SetOp(INS_CMP, 0xc9, ADDR_IMM, 2, 2);
            SetOp(INS_CMP, 0xc5, ADDR_ZP, 2, 3);
            SetOp(INS_CMP, 0xd5, ADDR_ZPX, 2, 4);
            SetOp(INS_CMP, 0xcd, ADDR_ABS, 3, 4);
            SetOp(INS_CMP, 0xdd, ADDR_ABSX, 3, 4);
            SetOp(INS_CMP, 0xd9, ADDR_ABSY, 3, 4);
            SetOp(INS_CMP, 0xc1, ADDR_IDX, 2, 6);
            SetOp(INS_CMP, 0xd1, ADDR_IDY, 2, 5);

            // CPX:
            SetOp(INS_CPX, 0xe0, ADDR_IMM, 2, 2);
            SetOp(INS_CPX, 0xe4, ADDR_ZP, 2, 3);
            SetOp(INS_CPX, 0xec, ADDR_ABS, 3, 4);

            // CPY:
            SetOp(INS_CPY, 0xc0, ADDR_IMM, 2, 2);
            SetOp(INS_CPY, 0xc4, ADDR_ZP, 2, 3);
            SetOp(INS_CPY, 0xcc, ADDR_ABS, 3, 4);

            // DEC:
            SetOp(INS_DEC, 0xc6, ADDR_ZP, 2, 5);
            SetOp(INS_DEC, 0xd6, ADDR_ZPX, 2, 6);
            SetOp(INS_DEC, 0xce, ADDR_ABS, 3, 6);
            SetOp(INS_DEC, 0xde, ADDR_ABSX, 3, 7);

            // DEX:
            SetOp(INS_DEX, 0xca, ADDR_IMP, 1, 2);

            // DEY:
            SetOp(INS_DEY, 0x88, ADDR_IMP, 1, 2);

            // EOR:
            SetOp(INS_EOR, 0x49, ADDR_IMM, 2, 2);
            SetOp(INS_EOR, 0x45, ADDR_ZP, 2, 3);
            SetOp(INS_EOR, 0x55, ADDR_ZPX, 2, 4);
            SetOp(INS_EOR, 0x4d, ADDR_ABS, 3, 4);
            SetOp(INS_EOR, 0x5d, ADDR_ABSX, 3, 4);
            SetOp(INS_EOR, 0x59, ADDR_ABSY, 3, 4);
            SetOp(INS_EOR, 0x41, ADDR_IDX, 2, 6);
            SetOp(INS_EOR, 0x51, ADDR_IDY, 2, 5);

            // INC:
            SetOp(INS_INC, 0xe6, ADDR_ZP, 2, 5);
            SetOp(INS_INC, 0xf6, ADDR_ZPX, 2, 6);
            SetOp(INS_INC, 0xee, ADDR_ABS, 3, 6);
            SetOp(INS_INC, 0xfe, ADDR_ABSX, 3, 7);

            // INX:
            SetOp(INS_INX, 0xe8, ADDR_IMP, 1, 2);

            // INY:
            SetOp(INS_INY, 0xc8, ADDR_IMP, 1, 2);

            // JMP:
            SetOp(INS_JMP, 0x4c, ADDR_ABS, 3, 3);
            SetOp(INS_JMP, 0x6c, ADDR_INDABS, 3, 5);

            // JSR:
            SetOp(INS_JSR, 0x20, ADDR_ABS, 3, 6);

            // LDA:
            SetOp(INS_LDA, 0xa9, ADDR_IMM, 2, 2);
            SetOp(INS_LDA, 0xa5, ADDR_ZP, 2, 3);
            SetOp(INS_LDA, 0xb5, ADDR_ZPX, 2, 4);
            SetOp(INS_LDA, 0xad, ADDR_ABS, 3, 4);
            SetOp(INS_LDA, 0xbd, ADDR_ABSX, 3, 4);
            SetOp(INS_LDA, 0xb9, ADDR_ABSY, 3, 4);
            SetOp(INS_LDA, 0xa1, ADDR_IDX, 2, 6);
            SetOp(INS_LDA, 0xb1, ADDR_IDY, 2, 5);

            // LDX:
            SetOp(INS_LDX, 0xa2, ADDR_IMM, 2, 2);
            SetOp(INS_LDX, 0xa6, ADDR_ZP, 2, 3);
            SetOp(INS_LDX, 0xb6, ADDR_ZPY, 2, 4);
            SetOp(INS_LDX, 0xae, ADDR_ABS, 3, 4);
            SetOp(INS_LDX, 0xbe, ADDR_ABSY, 3, 4);

            // LDY:
            SetOp(INS_LDY, 0xa0, ADDR_IMM, 2, 2);
            SetOp(INS_LDY, 0xa4, ADDR_ZP, 2, 3);
            SetOp(INS_LDY, 0xb4, ADDR_ZPX, 2, 4);
            SetOp(INS_LDY, 0xac, ADDR_ABS, 3, 4);
            SetOp(INS_LDY, 0xbc, ADDR_ABSX, 3, 4);

            // LSR:
            SetOp(INS_LSR, 0x4a, ADDR_ACC, 1, 2);
            SetOp(INS_LSR, 0x46, ADDR_ZP, 2, 5);
            SetOp(INS_LSR, 0x56, ADDR_ZPX, 2, 6);
            SetOp(INS_LSR, 0x4e, ADDR_ABS, 3, 6);
            SetOp(INS_LSR, 0x5e, ADDR_ABSX, 3, 7);

            // NOP:
            SetOp(INS_NOP, 0x1a, ADDR_IMP, 1, 2);
            SetOp(INS_NOP, 0x3a, ADDR_IMP, 1, 2);
            SetOp(INS_NOP, 0x5a, ADDR_IMP, 1, 2);
            SetOp(INS_NOP, 0x7a, ADDR_IMP, 1, 2);
            SetOp(INS_NOP, 0xda, ADDR_IMP, 1, 2);
            SetOp(INS_NOP, 0xea, ADDR_IMP, 1, 2);
            SetOp(INS_NOP, 0xfa, ADDR_IMP, 1, 2);

            // ORA:
            SetOp(INS_ORA, 0x09, ADDR_IMM, 2, 2);
            SetOp(INS_ORA, 0x05, ADDR_ZP, 2, 3);
            SetOp(INS_ORA, 0x15, ADDR_ZPX, 2, 4);
            SetOp(INS_ORA, 0x0d, ADDR_ABS, 3, 4);
            SetOp(INS_ORA, 0x1d, ADDR_ABSX, 3, 4);
            SetOp(INS_ORA, 0x19, ADDR_ABSY, 3, 4);
            SetOp(INS_ORA, 0x01, ADDR_IDX, 2, 6);
            SetOp(INS_ORA, 0x11, ADDR_IDY, 2, 5);

            // PHA:
            SetOp(INS_PHA, 0x48, ADDR_IMP, 1, 3);

            // PHP:
            SetOp(INS_PHP, 0x08, ADDR_IMP, 1, 3);

            // PLA:
            SetOp(INS_PLA, 0x68, ADDR_IMP, 1, 4);

            // PLP:
            SetOp(INS_PLP, 0x28, ADDR_IMP, 1, 4);

            // ROL:
            SetOp(INS_ROL, 0x2a, ADDR_ACC, 1, 2);
            SetOp(INS_ROL, 0x26, ADDR_ZP, 2, 5);
            SetOp(INS_ROL, 0x36, ADDR_ZPX, 2, 6);
            SetOp(INS_ROL, 0x2e, ADDR_ABS, 3, 6);
            SetOp(INS_ROL, 0x3e, ADDR_ABSX, 3, 7);

            // ROR:
            SetOp(INS_ROR, 0x6a, ADDR_ACC, 1, 2);
            SetOp(INS_ROR, 0x66, ADDR_ZP, 2, 5);
            SetOp(INS_ROR, 0x76, ADDR_ZPX, 2, 6);
            SetOp(INS_ROR, 0x6e, ADDR_ABS, 3, 6);
            SetOp(INS_ROR, 0x7e, ADDR_ABSX, 3, 7);

            // RTI:
            SetOp(INS_RTI, 0x40, ADDR_IMP, 1, 6);

            // RTS:
            SetOp(INS_RTS, 0x60, ADDR_IMP, 1, 6);

            // SBC:
            SetOp(INS_SBC, 0xe9, ADDR_IMM, 2, 2);
            SetOp(INS_SBC, 0xe5, ADDR_ZP, 2, 3);
            SetOp(INS_SBC, 0xf5, ADDR_ZPX, 2, 4);
            SetOp(INS_SBC, 0xed, ADDR_ABS, 3, 4);
            SetOp(INS_SBC, 0xfd, ADDR_ABSX, 3, 4);
            SetOp(INS_SBC, 0xf9, ADDR_ABSY, 3, 4);
            SetOp(INS_SBC, 0xe1, ADDR_IDX, 2, 6);
            SetOp(INS_SBC, 0xf1, ADDR_IDY, 2, 5);

            // SEC:
            SetOp(INS_SEC, 0x38, ADDR_IMP, 1, 2);

            // SED:
            SetOp(INS_SED, 0xf8, ADDR_IMP, 1, 2);

            // SEI:
            SetOp(INS_SEI, 0x78, ADDR_IMP, 1, 2);

            // STA:
            SetOp(INS_STA, 0x85, ADDR_ZP, 2, 3);
            SetOp(INS_STA, 0x95, ADDR_ZPX, 2, 4);
            SetOp(INS_STA, 0x8d, ADDR_ABS, 3, 4);
            SetOp(INS_STA, 0x9d, ADDR_ABSX, 3, 5);
            SetOp(INS_STA, 0x99, ADDR_ABSY, 3, 5);
            SetOp(INS_STA, 0x81, ADDR_IDX, 2, 6);
            SetOp(INS_STA, 0x91, ADDR_IDY, 2, 6);

            // STX:
            SetOp(INS_STX, 0x86, ADDR_ZP, 2, 3);
            SetOp(INS_STX, 0x96, ADDR_ZPY, 2, 4);
            SetOp(INS_STX, 0x8e, ADDR_ABS, 3, 4);

            // STY:
            SetOp(INS_STY, 0x84, ADDR_ZP, 2, 3);
            SetOp(INS_STY, 0x94, ADDR_ZPX, 2, 4);
            SetOp(INS_STY, 0x8c, ADDR_ABS, 3, 4);

            // TAX:
            SetOp(INS_TAX, 0xaa, ADDR_IMP, 1, 2);

            // TAY:
            SetOp(INS_TAY, 0xa8, ADDR_IMP, 1, 2);

            // TSX:
            SetOp(INS_TSX, 0xba, ADDR_IMP, 1, 2);

            // TXA:
            SetOp(INS_TXA, 0x8a, ADDR_IMP, 1, 2);

            // TXS:
            SetOp(INS_TXS, 0x9a, ADDR_IMP, 1, 2);

            // TYA:
            SetOp(INS_TYA, 0x98, ADDR_IMP, 1, 2);

            // ALR:
            SetOp(INS_ALR, 0x4b, ADDR_IMM, 2, 2);

            // ANC:
            SetOp(INS_ANC, 0x0b, ADDR_IMM, 2, 2);
            SetOp(INS_ANC, 0x2b, ADDR_IMM, 2, 2);

            // ARR:
            SetOp(INS_ARR, 0x6b, ADDR_IMM, 2, 2);

            // AXS:
            SetOp(INS_AXS, 0xcb, ADDR_IMM, 2, 2);

            // LAX:
            SetOp(INS_LAX, 0xa3, ADDR_IDX, 2, 6);
            SetOp(INS_LAX, 0xa7, ADDR_ZP, 2, 3);
            SetOp(INS_LAX, 0xaf, ADDR_ABS, 3, 4);
            SetOp(INS_LAX, 0xb3, ADDR_IDY, 2, 5);
            SetOp(INS_LAX, 0xb7, ADDR_ZPY, 2, 4);
            SetOp(INS_LAX, 0xbf, ADDR_ABSY, 3, 4);

            // SAX:
            SetOp(INS_SAX, 0x83, ADDR_IDX, 2, 6);
            SetOp(INS_SAX, 0x87, ADDR_ZP, 2, 3);
            SetOp(INS_SAX, 0x8f, ADDR_ABS, 3, 4);
            SetOp(INS_SAX, 0x97, ADDR_ZPY, 2, 4);

            // DCP:
            SetOp(INS_DCP, 0xc3, ADDR_IDX, 2, 8);
            SetOp(INS_DCP, 0xc7, ADDR_ZP, 2, 5);
            SetOp(INS_DCP, 0xcf, ADDR_ABS, 3, 6);
            SetOp(INS_DCP, 0xd3, ADDR_IDY, 2, 8);
            SetOp(INS_DCP, 0xd7, ADDR_ZPX, 2, 6);
            SetOp(INS_DCP, 0xdb, ADDR_ABSY, 3, 7);
            SetOp(INS_DCP, 0xdf, ADDR_ABSX, 3, 7);

            // ISC:
            SetOp(INS_ISC, 0xe3, ADDR_IDX, 2, 8);
            SetOp(INS_ISC, 0xe7, ADDR_ZP, 2, 5);
            SetOp(INS_ISC, 0xef, ADDR_ABS, 3, 6);
            SetOp(INS_ISC, 0xf3, ADDR_IDY, 2, 8);
            SetOp(INS_ISC, 0xf7, ADDR_ZPX, 2, 6);
            SetOp(INS_ISC, 0xfb, ADDR_ABSY, 3, 7);
            SetOp(INS_ISC, 0xff, ADDR_ABSX, 3, 7);

            // RLA:
            SetOp(INS_RLA, 0x23, ADDR_IDX, 2, 8);
            SetOp(INS_RLA, 0x27, ADDR_ZP, 2, 5);
            SetOp(INS_RLA, 0x2f, ADDR_ABS, 3, 6);
            SetOp(INS_RLA, 0x33, ADDR_IDY, 2, 8);
            SetOp(INS_RLA, 0x37, ADDR_ZPX, 2, 6);
            SetOp(INS_RLA, 0x3b, ADDR_ABSY, 3, 7);
            SetOp(INS_RLA, 0x3f, ADDR_ABSX, 3, 7);

            // RRA:
            SetOp(INS_RRA, 0x63, ADDR_IDX, 2, 8);
            SetOp(INS_RRA, 0x67, ADDR_ZP, 2, 5);
            SetOp(INS_RRA, 0x6f, ADDR_ABS, 3, 6);
            SetOp(INS_RRA, 0x73, ADDR_IDY, 2, 8);
            SetOp(INS_RRA, 0x77, ADDR_ZPX, 2, 6);
            SetOp(INS_RRA, 0x7b, ADDR_ABSY, 3, 7);
            SetOp(INS_RRA, 0x7f, ADDR_ABSX, 3, 7);

            // SLO:
            SetOp(INS_SLO, 0x03, ADDR_IDX, 2, 8);
            SetOp(INS_SLO, 0x07, ADDR_ZP, 2, 5);
            SetOp(INS_SLO, 0x0f, ADDR_ABS, 3, 6);
            SetOp(INS_SLO, 0x13, ADDR_IDY, 2, 8);
            SetOp(INS_SLO, 0x17, ADDR_ZPX, 2, 6);
            SetOp(INS_SLO, 0x1b, ADDR_ABSY, 3, 7);
            SetOp(INS_SLO, 0x1f, ADDR_ABSX, 3, 7);

            // SRE:
            SetOp(INS_SRE, 0x43, ADDR_IDX, 2, 8);
            SetOp(INS_SRE, 0x47, ADDR_ZP, 2, 5);
            SetOp(INS_SRE, 0x4f, ADDR_ABS, 3, 6);
            SetOp(INS_SRE, 0x53, ADDR_IDY, 2, 8);
            SetOp(INS_SRE, 0x57, ADDR_ZPX, 2, 6);
            SetOp(INS_SRE, 0x5b, ADDR_ABSY, 3, 7);
            SetOp(INS_SRE, 0x5f, ADDR_ABSX, 3, 7);

            // SKB:
            SetOp(INS_SKB, 0x80, ADDR_IMM, 2, 2);
            SetOp(INS_SKB, 0x82, ADDR_IMM, 2, 2);
            SetOp(INS_SKB, 0x89, ADDR_IMM, 2, 2);
            SetOp(INS_SKB, 0xc2, ADDR_IMM, 2, 2);
            SetOp(INS_SKB, 0xe2, ADDR_IMM, 2, 2);

            // SKB:
            SetOp(INS_IGN, 0x0c, ADDR_ABS, 3, 4);
            SetOp(INS_IGN, 0x1c, ADDR_ABSX, 3, 4);
            SetOp(INS_IGN, 0x3c, ADDR_ABSX, 3, 4);
            SetOp(INS_IGN, 0x5c, ADDR_ABSX, 3, 4);
            SetOp(INS_IGN, 0x7c, ADDR_ABSX, 3, 4);
            SetOp(INS_IGN, 0xdc, ADDR_ABSX, 3, 4);
            SetOp(INS_IGN, 0xfc, ADDR_ABSX, 3, 4);
            SetOp(INS_IGN, 0x04, ADDR_ZP, 2, 3);
            SetOp(INS_IGN, 0x44, ADDR_ZP, 2, 3);
            SetOp(INS_IGN, 0x64, ADDR_ZP, 2, 3);
            SetOp(INS_IGN, 0x14, ADDR_ZPX, 2, 4);
            SetOp(INS_IGN, 0x34, ADDR_ZPX, 2, 4);
            SetOp(INS_IGN, 0x54, ADDR_ZPX, 2, 4);
            SetOp(INS_IGN, 0x74, ADDR_ZPX, 2, 4);
            SetOp(INS_IGN, 0xd4, ADDR_ZPX, 2, 4);
            SetOp(INS_IGN, 0xf4, ADDR_ZPX, 2, 4);
        }

        /// <summary>
        /// 0-7 inst
        /// 8-15 addr
        /// 16-23 size
        /// 24-31 cycles
        /// </summary>
        /// <param name="inst"></param>
        /// <param name="op"></param>
        /// <param name="addr"></param>
        /// <param name="size"></param>
        /// <param name="cycles"></param>
        private static void SetOp(Int32 inst, Int32 op, Int32 addr, Int32 size, Int32 cycles)
        {
            //Opcodes[op] =
            //  (inst & 0xff) |
            //  ((addr & 0xff) << 8) |
            //  ((size & 0xff) << 16) |
            //  ((cycles & 0xff) << 24);
            Opcodes[op] = [(Byte)inst, (Byte)addr, (Byte)size, (Byte)cycles];

        }
    }
}
